﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics.Contracts;
using HeapSpecSupport;
using SimpleIR;

namespace Evaluator.EvalState
{
	/// <summary>
	/// Abstract class representing a memory location in the program. Possible types of memory locations are: 
	/// (1) Objects allocated on the heap.
	/// (2) Fixed storage locations for locals and globals.
	/// </summary>
	internal abstract class ELocation
	{
		protected readonly IRType m_loctype;

		/// <summary>
		/// The position of this location in the memory.
		/// </summary>
		private int m_locationaddress;

		/// <summary>
		/// A unique id we give to this location so you can track it easily.
		/// </summary>
		internal readonly ulong LocationUniqueID;

		private static ulong idgen = 0;

		internal ELocation(int address, IRType loctype)
		{
			Contract.Requires(loctype != null);

			this.m_loctype = loctype;
			this.m_locationaddress = address;
			this.LocationUniqueID = idgen++;
		}

		/// <summary>
		/// Get the type of the location
		/// </summary>
		internal IRType LocationType
		{ get { return this.m_loctype; } }

		/// <summary>
		/// Get the address of the location
		/// </summary>
		internal int Address
		{ get { return this.m_locationaddress; } }

		/// <summary>
		/// For use in GC compacting.
		/// </summary>
		internal void UpdateLocationAddress(int newaddr)
		{ this.m_locationaddress = newaddr; }

		/// <summary>
		/// Do a read from the given BAP in the location.
		/// </summary>
		internal abstract EValue DoSimpleValueReadFromLocation(int arrayidx, IRBasicAccessPath bap, ulong time, long line);

		/// <summary>
		/// Do a write to the given BAP in the location.
		/// </summary>
		internal abstract void DoSimpleValueWriteToLocation(int arrayidx, IRBasicAccessPath bap, EValue nval, ulong time, long line);

		/// <summary>
		/// Mark that the contents at a given location were read.
		/// </summary>
		internal abstract void DoCompoundReadFromLocation(int arrayidx, IRBasicAccessPath bap, BAPLayoutMap into, ulong time, long line);

		/// <summary>
		/// Mark that the contents at a given location were writtn.
		/// </summary>
		internal abstract void DoCompoundWriteToLocation(int arrayidx, IRBasicAccessPath bap, BAPLayoutMap from, ulong time, long line);
	}

	/// <summary>
	/// Simple by-value type for tracking the allocation information of a location.
	/// </summary>
	internal struct AllocRecord
	{
		internal readonly ulong AllocTime;
		internal readonly long AllocLine;

		internal AllocRecord(ulong time, long line)
		{
			this.AllocTime = time;
			this.AllocLine = line;
		}

		public override string ToString()
		{ return String.Format("Alloc: {0:d}T {1:d}L", this.AllocTime, this.AllocLine); }
	}
}
